package cn.demoncat.util.lang.entity.report;

import cn.demoncat.util.lang.LocalDateUtil;
import cn.demoncat.util.lang.ParamEmptyUtil;
import cn.demoncat.util.lang.constant.DateConstant;
import cn.demoncat.util.lang.constant.ReportConstant;
import cn.demoncat.util.mybatis.constant.MapperConstant;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 报表参数 - 周期图表
 * 
 * @author 延晓磊
 *
 * @since 2019年12月11日
 */
public class ReportParamChartPeriod {

	// 图表模式：ReportConstant.ModePeriod
	private String mode;
	// 统计周期数
	private Integer num;
	// 数据起始时间： startTime <= date
	private LocalDateTime startTime;
	// 数据结束时间：endTime > date
	private LocalDateTime endTime;
	// 分组字段
	private String groupColumns;
	
	/**
	 * 获取周期图表参数 - 单维度
	 * 
	 * @param mode			模式：ReportConstant.ModePeriod
	 * @param num			周期数
	 * @param date			基准日期(结束周期)，默认当前
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年12月11日
	 */
	public static ReportParamChartPeriod build(String mode, Integer num, LocalDateTime date){
		return build(mode, num, date, false, false);
	}
	
	/**
	 * 获取周期图表参数 - 多维度
	 * 
	 * @param mode			模式：ReportConstant.ModePeriod
	 * @param num			周期数
	 * @param date			基准日期(结束周期)，默认当前
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年12月11日
	 */
	public static ReportParamChartPeriod buildMulit(String mode, Integer num, LocalDateTime date){
		return build(mode, num, date, true, false);
	}
	
	/**
	 * 获取周期图表参数 - 单/多维度
	 * 
	 * @param mode			模式：ReportConstant.ModePeriod
	 * @param num			周期数
	 * @param date			基准日期(结束周期)，默认当前
	 * @param countItem		是否多维统计Item项：多维度为true
	 * @param countTitle	是否多维统计Item项，并展示Title：用于多维度并且根据数据周期获取Legend的情况，这种数据Title须与Item保持一致不能变动
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年12月11日
	 */
	public static ReportParamChartPeriod build(String mode, Integer num, LocalDateTime date, boolean countItem, boolean countTitle){
		// 参数校验
		ParamEmptyUtil.checkBlank(mode);
		if (num == null || num < 1) {
			throw ReportConstant.DYNAMIC_CHART_NUM_ERROR;
		}
		// 基准日期：默认当前
		if (date == null) {
			date = LocalDateTime.now();
		}
		ReportParamChartPeriod param = new ReportParamChartPeriod();
		param.setMode(mode);
		param.setNum(num);
		num = num -1;
		// 模式
		switch (mode) {
		case ReportConstant.ModePeriod.HOUR:
			// 时
			date = LocalDateUtil.startOfHour(date);
			param.setStartTime(date.minusHours(num));
			param.setEndTime(date.plusHours(1));
			// 分组字段
			if (countItem) {
				if (countTitle) {
					param.setColumns(ReportConstant.Column.HOUR_ITEM_TITLE);
				}else {
					param.setColumns(ReportConstant.Column.HOUR_ITEM);
				}
			}else {
				param.setColumns(ReportConstant.Column.HOUR);
			}
			return param;
		case ReportConstant.ModePeriod.DAY:
			// 日
			date = LocalDateUtil.startOfDay(date);
			param.setStartTime(date.minusDays(num));
			param.setEndTime(date.plusDays(1));
			// 分组字段
			if (countItem) {
				if (countTitle) {
					param.setColumns(ReportConstant.Column.DAY_ITEM_TITLE);
				}else {
					param.setColumns(ReportConstant.Column.DAY_ITEM);
				}
			}else {
				param.setColumns(ReportConstant.Column.DAY);
			}
			return param;
		case ReportConstant.ModePeriod.MONTH:
			// 月
			date = LocalDateUtil.startOfMonth(date);
			param.setStartTime(date.minusMonths(num));
			param.setEndTime(date.plusMonths(1));
			// 分组字段
			if (countItem) {
				if (countTitle) {
					param.setColumns(ReportConstant.Column.MONTH_ITEM_TITLE);
				}else {
					param.setColumns(ReportConstant.Column.MONTH_ITEM);
				}
			}else {
				param.setColumns(ReportConstant.Column.MONTH);
			}
			return param;
		case ReportConstant.ModePeriod.YEAR:
			// 年
			date = LocalDateUtil.startOfYear(date);
			param.setStartTime(date.minusYears(num));
			param.setEndTime(date.plusYears(1));
			// 分组字段
			if (countItem) {
				if (countTitle) {
					param.setColumns(ReportConstant.Column.YEAR_ITEM_TITLE);
				}else {
					param.setColumns(ReportConstant.Column.YEAR_ITEM);
				}
			}else {
				param.setColumns(ReportConstant.Column.YEAR);
			}
			return param;
		case ReportConstant.ModePeriod.WEEK:
			// 周
			date = LocalDateUtil.startOfWeek(date);
			param.setStartTime(date.minusWeeks(num));
			param.setEndTime(date.plusWeeks(1));
			// 分组字段：统计为日，然后累加
			if (countItem) {
				if (countTitle) {
					param.setColumns(ReportConstant.Column.DAY_ITEM_TITLE);
				}else {
					param.setColumns(ReportConstant.Column.DAY_ITEM);
				}
			}else {
				param.setColumns(ReportConstant.Column.DAY);
			}
			return param;
		case ReportConstant.ModePeriod.QUARTER:
			// 季
			date = LocalDateUtil.startOfQuarter(date);
			param.setStartTime(LocalDateUtil.minusQuarter(date, num));
			param.setEndTime(LocalDateUtil.plusQuarter(date, 1));
			// 分组字段：统计为月，然后累加
			if (countItem) {
				if (countTitle) {
					param.setColumns(ReportConstant.Column.MONTH_ITEM_TITLE);
				}else {
					param.setColumns(ReportConstant.Column.MONTH_ITEM);
				}
			}else {
				param.setColumns(ReportConstant.Column.MONTH);
			}
			return param;
		default:
			throw ReportConstant.CHART_MODE_ERROR;
		}
	}
 
	/**
	 * 整合周期图表查询参数
	 * 
	 * @param condition	查询参数：type,item,...
	 * 
	 * @return {查询参数，startTime, endTime, groupColumns}
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年12月11日
	 */
	public Map<String, Object> getParams(Map<String, Object> condition){
		// 参数校验
		if (condition == null) {
			condition = new HashMap<>();
		}
		// 整合查询条件
		condition.put(MapperConstant.ParamName.START_TIME, this.getStartTime());
		condition.put(MapperConstant.ParamName.END_TIME, this.getEndTime());
		condition.put(MapperConstant.ParamName.GROUP_COLUMNS, this.getGroupColumns());
		return condition;
	}
	
	/**
	 * 获取周期的日期
	 * 
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020-9-11
	 */
	public List<String> getDates(){
		List<String> dates = new ArrayList<>();
		LocalDateTime startTime = this.getStartTime();
		switch (this.getMode()) {
		case ReportConstant.ModePeriod.HOUR:
			// 时
			for (int i = 0; i < this.getNum(); i++) {
				dates.add(startTime.format(DateConstant.DATE_HOUR_FORMAT));
				startTime = startTime.plusHours(1);
			}
			break;
		case ReportConstant.ModePeriod.DAY:
			// 日
			for (int i = 0; i < this.getNum(); i++) {
				dates.add(startTime.format(DateConstant.DATE_FROMAT));
				startTime = startTime.plusDays(1);
			}
			break;
		case ReportConstant.ModePeriod.MONTH:
			// 月
			for (int i = 0; i < this.getNum(); i++) {
				dates.add(startTime.format(DateConstant.MONTH_FORMAT));
				startTime = startTime.plusMonths(1);
			}
			break;
		case ReportConstant.ModePeriod.YEAR:
			// 年
			for (int i = 0; i < this.getNum(); i++) {
				dates.add(String.valueOf(startTime.getYear()));
				startTime = startTime.plusYears(1);
			}
			break;
		case ReportConstant.ModePeriod.WEEK:
			// 周
			for (int i = 0; i < this.getNum(); i++) {
				dates.add(startTime.format(DateConstant.DATE_FROMAT));
				startTime = startTime.plusWeeks(1);
			}
			break;
		case ReportConstant.ModePeriod.QUARTER:
			// 季
			for (int i = 0; i < this.getNum(); i++) {
				dates.add(startTime.format(DateConstant.MONTH_FORMAT));
				startTime = LocalDateUtil.plusQuarter(startTime, 1);
			}
			break;
		default:
			throw ReportConstant.CHART_MODE_ERROR;
		}
		return dates;
	}
	
	/**
	 * 设置分组字段
	 * 
	 * @param column
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年12月11日
	 */
	private void setColumns(ReportConstant.Column column) {
		this.groupColumns = column.getGroupColumns();
	}
	
	public String getMode() {
		return mode;
	}

	public void setMode(String mode) {
		this.mode = mode;
	}

	public Integer getNum() {
		return num;
	}

	public void setNum(Integer num) {
		this.num = num;
	}

	public LocalDateTime getStartTime() {
		return startTime;
	}

	public void setStartTime(LocalDateTime startTime) {
		this.startTime = startTime;
	}

	public LocalDateTime getEndTime() {
		return endTime;
	}

	public void setEndTime(LocalDateTime endTime) {
		this.endTime = endTime;
	}

	public String getGroupColumns() {
		return groupColumns;
	}

	public void setGroupColumns(String groupColumns) {
		this.groupColumns = groupColumns;
	}
}
